/*******************************************************************************************
Copyright (C) 2013 Mestrelab Research S.L. All rights reserved.

This file is part of the Mnova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*******************************************************************************************/

/*globals mainWindow, nmr, settings, FileDialog, serialization, Dir, File, BinaryStream, NMRPredictorParams, ProgressDialog, Str, TextStream, Application, NMRSpectrum, MnUi*/
/*jslint plusplus: true, indent: 4, bitwise: true*/

function importAcdlabsEsp() {
	"use strict";

	function acdNuc2Str(aNuc) {
		switch (aNuc) {
		case 1:
			return "1H";
		case 2:
			return "13C";
		}
	}

	var fi, fileName, fin, sin, len, signature, ftFlag, npts, freq, nuc, sw, sc, paramsOk,
		parId, size, reArr, i, dPpm, ppm, proc, imgArray, spectrum, startPpm, progressBar,
		openDir, fileNames, nucleus, specSize, fromPPM, endPPM, dirSetKey, refFreq;

	dirSetKey = "importAcdlabsEsp/Dir";
	openDir = settings.value(dirSetKey, Dir.home());
	fileNames = FileDialog.getOpenFileNames("ACDLabs 1D NMR (*.esp)", "", openDir);
	if (!fileNames.length) {
		return;
	}

	//Create a progress bar in order to inform to the user about the state of the import process
	progressBar = new ProgressDialog();
	progressBar.minimum = 0;
	progressBar.maximum = 100;
	progressBar.value = 0;
	progressBar.visible = true;

	serialization.fileHistory = false;
	for (fi = 0; fi < fileNames.length && !progressBar.wasCanceled; fi++) {
		fileName = fileNames[fi];
		fin = new File(fileName);

		if (!fi) {
			settings.setValue(dirSetKey, fin.absDirPath);
		}

		fin.open(File.ReadOnly);
		sin = new BinaryStream(fin);
		sin.endianness = BinaryStream.eLittle;

		progressBar.labelText = "Importing file: " + fileName;

		len = sin.readInt16();
		if (len !== 0x0C) {
			fin.close();
		} else {
			signature = sin.readBytes(len).toString();
			if (signature !== "(C) ACD 1994") {
				fin.close();
			} else {
				len = sin.readInt16();
				if (len !== 0x0E && len !== 0x10) {
					fin.close();
				} else {
					signature = sin.readBytes(len).toString();
					if (signature !== ".ESP.( V 1.0 )" && signature !== "D1EspVersionInfo") {
						fin.close();
					} else {
						if (signature === "D1EspVersionInfo") {
							len = sin.readInt16();
							sin.pos += len + 0x09;
						} else {
							sin.pos += 0x0B;
						}
						paramsOk = true;
						do {
							sin.pos -= 1;
							parId = sin.readInt8();
							size = sin.readInt8();
							switch (parId) {
							case 0x01:
								if (size !== 2) {
									paramsOk = false;
								}
								ftFlag = sin.readInt16();
								break;
							case 0x02:
								if (size !== 4) {
									paramsOk = false;
								}
								npts = sin.readInt32();
								break;
							case 0x03:
								if (size !== 4) {
									paramsOk = false;
								}
								sw = sin.readReal32();
								break;
							case 0x04:
								if (size !== 4) {
									paramsOk = false;
								}
								sc = sin.readReal32();
								break;
							case 0x05:
								if (size !== 4) {
									paramsOk = false;
								}
								freq = sin.readReal32();
								break;
							case 0x0C:
								if (size !== 1) {
									paramsOk = false;
								}
								nuc = sin.readInt8();
								break;
							default:
								sin.pos += size;
							}
						} while (paramsOk && sin.readInt8());

						//If for that reason frequency values is missing in header block, we use the default values written at TASCIINMRConverter
						//TASCIINMRConverter looks for entry "frequency" in the header. If there is no entry (but it's - it says "frequency undefined") it sets to 400.
						//Otherwise somewhere else it set it to default 300 stored at NMR General.cpp essentials::defMHz = 300.0;
						if (freq === "undefined" || freq === undefined) {
							freq = 400;
						} else if (isNaN(freq)) {
							freq = 300;
						}

						if (!paramsOk || !npts) {
							fin.close();
						} else {
							if (sin.readInt8()) {
								fin.close();
							} else {
								reArr = [];
								imgArray = [];
								for (i = 0; i < npts; i++) {
									reArr[i] = Number(sin.readReal32());
								}
								if (ftFlag & 0x01) {
									for (i = npts - 1; i >= 0; i--) {
										imgArray.push(Number(sin.readReal32()));
									}
								} else if (ftFlag & 0x02) {
									refFreq = freq - sc * 1e-6;
									dPpm = sw / npts / refFreq;
									ppm = (sc - 0.5 * sw) / refFreq - dPpm;
									startPpm = ppm;
									for (i = npts - 1; i >= 0; i--) {
										imgArray.push(Number(sin.readReal32()));
										ppm += dPpm;
									}
								}

								//Update progressBar and close the input file
								progressBar.value = (((sin.pos / fin.size) * 100) * ((fi + 1) / fileNames.length));
								fin.close();

								//It creates a NMR Spectrum
								specSize = npts;
								nucleus = acdNuc2Str(nuc);
								fromPPM = startPpm;
								endPPM = ppm;
								spectrum = importAcdlabsEsp.createSpectrum(specSize, nucleus, freq, fromPPM, endPPM, fileName);

								//It fills the spectrum
								if (spectrum !== undefined && spectrum.isValid()) {

									//Fill spectrum
									nmr.beginModification(spectrum);
									spectrum.setReal("all", reArr);
									spectrum.setImag("all", imgArray);
									nmr.endModification(spectrum);
									mainWindow.activeDocument.update();
									spectrum.update();

									//Apply processing template
									proc = spectrum.proc;
									if (ftFlag & 0x01) {
										proc.setParameter("FT[1].Invert", true);
										proc.setParameter("FT[1].Quadrature", true);
									}
									proc.setParameter("PC.Method", "Regions Analysis");
									mainWindow.doAction("nmrShowFT1");
									spectrum.process(proc);
									spectrum.update();
								}
							}
						}
					}
				}
			}
		}
	}
	if (Application.mainWindow.activeDocument !== undefined) {
		Application.mainWindow.activeDocument.update();
	}
	serialization.fileHistory = true;
	progressBar.value = 100;
	progressBar.visible = false;
}

importAcdlabsEsp.createSpectrum = function createSpectrum(aSize, aNuc, aMhz, aPpm1, aPpm2, aFilename) {
	"use strict";

	var result, predictorParameters, spectrum, peaks;

	result = {};

	predictorParameters = new NMRPredictorParams(aNuc);
	predictorParameters.frequency = aMhz;
	predictorParameters.fromPPM = aPpm1;
	predictorParameters.toPPM = aPpm2;
	predictorParameters.size = aSize;
	peaks = [];

	//Create spectrum object
	spectrum = new NMRSpectrum({args: [predictorParameters, peaks], metadata: {title: '', origin: 'ESP file', filename: aFilename}});

	return spectrum;
};

if (this.MnUi && MnUi.scripts_nmr) {
	MnUi.scripts_nmr.scripts_nmr_ImportACDLabs1DNMR = importAcdlabsEsp;
}
